
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include "evalsoc.h"
#include "dbg_cli.h"
#include "drv_qspi.h"


extern bool time_reached( uint64_t tmo );
extern int zmodem_cmd_recv( void * pdat, int maxs, int * plen );


static int rzlen = 0;

//接收文件到 ILM 位置
static int dbg_file_rzm( void * parg, int argc, const char * argv[] )
{
	int iret;
	int tlen;

	/* 传输到 ILM 开始位置. */
	iret = zmodem_cmd_recv( (void *)(uintptr_t)ONCHIP_ILM_BASE, 102400, &tlen );
	if ( iret != 0 )  {
		printf( "rz fail = %d\n", iret );
		return 122;
	}

	/**/
	rzlen = tlen;
	printf( "finish : ILM = 0x%lx : %d\n", ONCHIP_ILM_BASE, tlen );
	return 0;
}

//将ILM中的数据烧录到QSPI Flash中
static int dbg_flash_burn( void * parg, int argc, const char * argv[] )
{
	int iret;
	dw_qspi_regs_t * pqspi = (dw_qspi_regs_t *)0x2000000;

	iret = qspi_burn( pqspi, (uint8_t *)(uintptr_t)ONCHIP_ILM_BASE, rzlen );
	if ( iret != 0 )  {
		printf( "burn fail = %d\n", iret );
		return 122;
	}

	/**/
	return 0;
}

//跳转到指定地址
static int dbg_run_direct( void * parg, int argc, const char * argv[] )
{
	int iret;
	uint32_t temp;
	
	uintptr_t pjbuf[4];
	/**/
	if ( argc < 2 )
	{
		printf( "default to 0x%lx\n", ONCHIP_ILM_BASE );
		temp = ONCHIP_ILM_BASE;

	}  else {

		/**/
		iret = debug_str2uint( argv[1], &temp );
		if ( iret != 0 )
		{
			printf( "addr fmt error..%d.. \n", iret );
			return 123;
		}
	}

	//
	pjbuf[0] = (uintptr_t)ONCHIP_DLM_BASE;
	pjbuf[1] = (uintptr_t)temp;
	pjbuf[2] = (uintptr_t)(ONCHIP_DLM_BASE + 0x10000);
	pjbuf[3] = 0;

	__RWMB();
	__builtin_longjmp( pjbuf, 1 );//跳转到pjbuf[1]地址
	return 0;
}


int check_ascii_input( dw_uart_regs_t * puart, uint32_t dlys )
{
	int iret;
	uint64_t tmout;

	/**/
	tmout = time_make_timeout( dlys );

	while ( true )  {

		iret = uart_try_getch( puart );
		if ( (iret > 0) && (iret < 0x7F) ) {
			printf( "%02x\n", iret );
			return iret;
		}

		if ( time_reached( tmout) )  {
			return -201;
		}
	}
}

int dbg_load_way( void * parg, int argc, const char * argv[] ){

	int iret;
	char spad[128];
	dw_qspi_regs_t *pqspi = (dw_qspi_regs_t *)0x2000000;

	if ( argc < 2 )  {
		goto usage;
	}
	if(0 == strcmp( argv[1], "xip1" ) )  {
		printf("flash_xip_way 1 line---0x03\n");

		REG32( 0x200000 + 0x10 ) = 0x4;//xip_en = 0;

		pqspi->SSIENR = 0;

		//SPI_CTRLR0.XIP_DFS_HC(19位)使能为1
		//修复XIP传输的DFS。如果此位设置为1，则XIP传输的数据帧大小将固定为CTRLR0.DFS中的编程值。
		//要获取的数据帧的数量将由HSIZE和HBURST信号决定。
		//如果该位设置为0，则数据帧大小和要提取的数据帧数量将由HSIZE和HBURST信号决定
		pqspi->CTRLR0 = 0x807;
		pqspi->SPI_CTRLR0 = 0x8180218;
		pqspi->XIP_INCR_INST = 0x03;//Read Data Bytes (READ) (03H) command

		pqspi->SSIENR = 1;

		REG32( 0x200000 + 0x10 ) = 0x5;//xip_en = 1;
	}
	if(0 == strcmp( argv[1], "xip2" ) )  {

		printf("flash_xip_way 2 lines--0x3B\n");

		REG32( 0x200000 + 0x10 ) = 0x4;

		pqspi->SSIENR = 0;

		// xip 两线配置：
		pqspi->CTRLR0 = 0x400807;//Dual SPI Format,TX_ONLY,07-bit serial data transfer
		pqspi->SPI_CTRLR0 = 0x8184218;
		pqspi->XIP_INCR_INST = 0x3B;//Dual Output Fast Read (3BH) command
		pqspi->SSIENR = 1;

		REG32( 0x200000 + 0x10 ) = 0x5;
	}
	if(0 == strcmp( argv[1], "xip4" ) )  {

		printf("flash_xip_way 4 lines--0x6B\n");

		REG32( 0x200000 + 0x10 ) = 0x4; 

		pqspi->SSIENR = 0;

		//xip 四线配置(6B命令)：
		pqspi->CTRLR0 = 0x800807;//Qual SPI Format,TX_ONLY,07-bit serial data transfer
		pqspi->SPI_CTRLR0 = 0x8184218;
		pqspi->XIP_INCR_INST = 0x6B;//Quad Output Fast Read (6BH) command

		pqspi->SSIENR = 1;

		REG32( 0x200000 + 0x10 ) = 0x5;
	}
	if(0 == strcmp( argv[1], "eb" ) )  {

		printf("flash_xip_way eb command--no instruction phase\n");

		REG32( 0x200000 + 0x10 ) = 0x4;


		/* 发送0xFF to flash  退出四线*/
		qspi_single_cmd( pqspi, 0xFF );

		//发送指令给flash(进入到0xEB模式，传输无需指令阶段模式)
		pqspi->SSIENR = 0;
		pqspi->SPI_CTRLR0 = 0x182221;
		pqspi->CTRLR0 = 0x800807;
		pqspi->TXFTLR = 0;
		pqspi->CTRLR1 = 1;
		pqspi->SSIENR = 1;
		// cmd = 0xEB
		pqspi->DR[0] = 0xEB;
		pqspi->DR[1] = 0x000000aa;
		pqspi->SER = 1;

		//延时
		for ( int i=0; i<1000; i++ )  {
			__NOP();
		}


		//xip 四线配置(EB命令-0xaa模式 无指令阶段)：
		pqspi->SSIENR = 0;
		pqspi->CTRLR0 = 0x800807;//Qual SPI Format,TX_ONLY,07-bit serial data transfer
		//EBh 需要enable SPI_CTRLR0.XIP_MD_BIT_EN(7位) 
		//disable SPI_CTRLR0.XIP_INST_EN(20位)  SPI_CTRLR0.INST_L(9:8 INST_L) = 0
		pqspi->SPI_CTRLR0 = 0x8082099;
		pqspi->XIP_MODE_BITS = 0xaa;
		pqspi->XIP_INCR_INST = 0xEB;//Quad I/O Fast Read (EBH) command
		pqspi->SSIENR = 1;

		REG32( 0x200000 + 0x10 ) = 0x5;

	}


	if(0 == strcmp( argv[1], "flash" ) )  {
	
		printf( "code load flash to ilm\n" );
		iret = qspi_load_flash( (void *)(uintptr_t)ONCHIP_ILM_BASE, 0x20000 );
		printf("iret = %d\n", iret);
		uintptr_t * pjbuf = (uintptr_t *)spad;

		pjbuf[0] = (uintptr_t)ONCHIP_DLM_BASE;
		pjbuf[1] = (uintptr_t)ONCHIP_ILM_BASE;
		pjbuf[2] = (uintptr_t)(ONCHIP_DLM_BASE + 0x10000);
		pjbuf[3] = 0;

		__RWMB();
		__builtin_longjmp( pjbuf, 1 );
	}
	return 0;
usage:
	printf( "load [xip1/2/4/eb|flash]\n" );
	printf( "xip1: 1 line xip mode-0x03\nxip2: 2 lines xip mode-0x3B\nxip4: 4 lines xip mode-0x6B\neb: no instruction phase xip mode-0xEB\nflash: load code to ilm\n" );
	return 0;
}

int main( void )
{
	int iret;
	char spad[128];

	printf( "\ncheck...\n" );

	

	// /* 等待 1-2 秒时间, 尝试从 uart 读取字符. */
	// iret = check_ascii_input( UART2, 80000000 );

	

	//flash check
	flash_execute();

	debug_cli_init();
	debug_add_cmd( "rz", dbg_file_rzm, NULL );
	debug_add_cmd( "burn", dbg_flash_burn, NULL );
	debug_add_cmd( "gogo", dbg_run_direct, NULL );

	debug_add_cmd( "qspi", qspi_test, NULL );
	debug_add_cmd( "fast----", qspi_cmd_fast, NULL );
	debug_add_cmd( "quad", qspi_cmd_fast, NULL );

	debug_add_cmd( "qq", qspi_Quad, NULL );
	debug_add_cmd( "qe", qspi_qe,NULL);

	debug_add_cmd( "load", dbg_load_way, NULL );

	/**/
	while ( true )  {

		/* read line */
		iret = cons_readline( ">> ", 120, spad );
		if ( iret != 0 ) {
			continue;
		}
			
		if ( 0 == strcmp( spad, "quit" ) )  {
			break;
		}

		/* proc */
		debug_proc_line( spad );
	}

	
}
